/**
 * @description For operations related to object model properties, after initializing the property list, you can read and write property values ​​using the get and set methods.

* `get` will first retrieve the value from memory; if the value is not found there, it will retrieve the default value. `set` will first modify the value in memory and then save it to the `property.json` file under the '/app/data/config/' directory.
 */

import dxMap from './dxMap.js'
import common from './dxCommon.js'
import std from './dxStd.js'

const property = {}
const map = dxMap.get('property')
const savePath = '/app/data/config/property.json'
property.all = map.get('all') || {}

/**
 * Initialization only needs to be done once, initializing all the property models' properties and their default values, as shown in the following example:
 * {
 *  "ui.showver":1,
 *  "sys.version":"version1.0.0"
 * }
 * @param {string} file The path to the JSON file containing all properties and their initial default values.
 * @returns 
 */
property.init = function (file) {
    if (map.get('___inited')) { // Initialize only once
        return
    }
    let all = std.parseExtJSON(std.loadFile('/app/code/' + file))
    all['sys.uuid'] = common.getUuid()
    property.all = all
    map.put('all', all)
    if (!std.exist(savePath)) {
        std.saveFile(savePath, '{}')
    }
    let content = std.parseExtJSON(std.loadFile(savePath))
    for (let [key, value] of Object.entries(content)) {
        map.put(key, value)
    }
    map.put('___inited', 'ok')
}

/**
 * Get the property value based on groupid and id, or get a group of properties. 
 * @param {string} groupId property group id, required.
 * @param {string} id The property id, optional. If not provided, all properties under the group will be returned.
 * @returns Returns an object where the key is 'groupid.id' and the value is the corresponding property value.
 * */
property.getValues = function (groupId, id) {
    if (!groupId) {
        throw new Error("property.getValues: 'groupId' should not be empty")
    }
    let res = {}
    if (!id) {
        let keys = Object.keys(property.all).filter(k => k.startsWith(groupId + '.'))//First, take the default value.
        keys.forEach(k => {
            res[k] = property.all[k];
        })
        keys = map.keys().filter(k => k.startsWith('property.' + groupId + '.'))//Then overwrite with actual values
        keys.forEach(k => {
            res[k.slice(9)] = map.get(k)
        })
    } else {
        const key = groupId + '.' + id
        res[key] = property.get(key)
    }
    return res
}
/**
 * get the corresponding property value based on 'groupid.id'
 * @param {string} key 'groupid.id'
 * @returns 
 */
property.get = function (key) {
    if (map.keys().includes('property.' + key)) {
        return map.get('property.' + key)
    }
    return property.all[key]
}
/**
 * set one or more property values.
 * @param {object} properties properties in the format {groupId.id: value}, supports setting multiple properties at once.
 */
property.setValues = function (properties) {
    if (!properties || typeof properties !== 'object') {
        throw new Error("property.setValues: 'properties' should not be empty and must be an object")
    }
    const keys = Object.keys(properties)
    if (keys.length <= 0) {
        return
    }
    keys.forEach(key => {
        map.put('property.' + key, properties[key])
    })
    save()
}
/**
 * set a property value with key/value
 * @param {string} key 'groupid.id'
 * @param {string} value  property value
 */
property.set = function (key, value) {
    if (!key) {
        throw new Error("property.set: 'key' should not be empty")
    }
    map.put('property.' + key, value)
    save()
}
/**
 * Restore factory settings, resetting all properties to their default values.
 */
property.reset = function () {
    common.systemBrief('rm -rf ' + savePath)
}

function save() {
    let configInfo = {}
    let keys = map.keys().filter(k => k.startsWith('property.'))
    keys.forEach(k => {
        let val = map.get(k)
        configInfo[k] = val
    })
    std.saveFile(savePath, JSON.stringify(configInfo))
}

export default property
